# 知识库和文档库 API 视图
import boto3
from django.conf import settings
from .minio_utils import upload_file_to_minio
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import KnowledgeBaseFile
from rest_framework.exceptions import ValidationError
from .serializers import KnowledgeBaseFileSerializer
from .models import KnowledgeBase
from .serializers import KnowledgeBaseSerializer
import logging
from utils.response import ResponseUtil

logger = logging.getLogger("knowledge_base")
ModelCode = "04"

class DocumentsView(APIView):
    def validate_params(params, required_params, types=None, format_checkers=None):
        """
        通用的参数检查函数。

        :param params: 请求中的参数（通常是 request.POST 或 request.GET）
        :param required_params: 必填参数的列表
        :param types: 参数类型的字典，如 {'param_name': type}，默认为 None
        :param format_checkers: 参数格式检查的字典，如 {'param_name': regex/validation_func}，默认为 None
        :return: 如果成功返回 True，检查失败则抛出 ValidationError 异常
        """
        missing_params = []
        invalid_params = []

        # 检查必选参数是否存在
        for param in required_params:
            if param not in params or not params[param]:
                missing_params.append(param)

        if missing_params:
            raise ValidationError({
                'error': 'Missing required parameters',
                'missing_params': missing_params
            })

        # 检查类型是否符合要求
        if types:
            for param, expected_type in types.items():
                if param in params:
                    value = params[param]
                    if not isinstance(value, expected_type):
                        invalid_params.append({
                            'param': param,
                            'error': f'Expected type {expected_type.__name__}, got {type(value).__name__}'
                        })

        # 检查格式是否符合要求
        if format_checkers:
            for param, checker in format_checkers.items():
                if param in params:
                    value = params[param]
                    if not checker(value):
                        invalid_params.append({
                            'param': param,
                            'error': f'Invalid format for {param}'
                        })

        if invalid_params:
            raise ValidationError({
                'error': 'Invalid parameter format',
                'invalid_params': invalid_params
            })


    def post(self,request):
        """
        文件上传接口，支持上传文件及元数据（如标签、来源、权限、是否启用等）。
        """

        # 检查文件是否存在
        if 'file' not in request.FILES:
            logger.error(f"Error: Missing file")
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error:Missing file")

        # 获取表单数据
        params = request.data

        # 定义必选参数
        required_params = ['tags', 'source', 'permissions', 'is_enabled']

        # 定义参数类型
        types = {
            'tags': str,
            'source': str,
            'permissions': str,
            'is_enabled': bool
        }

        # 定义格式检查器
        def source_format(value):
            return value in ['internal', 'external']

        def permissions_format(value):
            return value in ['high', 'medium', 'low']

        format_checkers = {
            'source': source_format,
            'permissions': permissions_format
        }

        # 调用验证函数
        try:
            self.validate_params(params, required_params, types, format_checkers)
        except ValidationError as e:
            logger.error(f"Error: {str(e)}")
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: File is required")

        # 获取上传文件
        uploaded_file = request.FILES['file']
        file_name = uploaded_file.name

        # 上传文件到 MinIO
        try:
            minio_path = upload_file_to_minio(uploaded_file, file_name)
        except Exception as e:
            logger.error(f"Error: upload file fail, {str(e)}")
            return ResponseUtil.error(code2=ModelCode, code3="02", message="error: upload file fail")

        # 获取其他参数
        tags = params.get('tags', '')
        source = params.get('source', 'internal')
        permissions = params.get('permissions', 'medium')
        is_enabled = params.get('is_enabled', True)
        knowledge_base_id = params.get('knowledge_base_id')

        # 保存文件信息到数据库
        new_file = KnowledgeBaseFile(
            file_name=file_name,
            tags=tags,
            source=source,
            permissions=permissions,
            is_enabled=is_enabled,
            knowledge_base_id=knowledge_base_id
        )
        new_file.save()

        # 返回成功响应
        return ResponseUtil.success(data={ 'file_path': minio_path,
            'file_name': file_name,
            'tags': tags,
            'source': source,
            'permissions': permissions,
            'is_enabled': is_enabled,
            'knowledge_base_id': knowledge_base_id})

    def get(self,request):
        try:
            # 获取查询参数
            tags_filter = request.GET.get('tags', None)
            source_filter = request.GET.get('source', None)
            permissions_filter = request.GET.get('permissions', None)

            if not tags_filter or not source_filter or not permissions_filter:
                return ResponseUtil.error(code2=ModelCode, code3="01", message="error: Missing required fields")

            # 筛选查询
            files_metadata = KnowledgeBaseFile.objects.all()

            if tags_filter:
                files_metadata = files_metadata.filter(tags__icontains=tags_filter)
            if source_filter:
                files_metadata = files_metadata.filter(source=source_filter)
            if permissions_filter:
                files_metadata = files_metadata.filter(permissions=permissions_filter)

            # 分页处理
            page = int(request.GET.get('page', 1))
            page_size = int(request.GET.get('page_size', 10))
            start = (page - 1) * page_size
            end = start + page_size
            files_metadata = files_metadata[start:end]

            # 将查询结果转换为列表
            files_metadata_list = list(files_metadata.values(
                'file_path', 'tags', 'source', 'permissions', 'is_enabled', 'knowledge_base_id'
            ))

            return ResponseUtil.success(data={'files_metadata_list': files_metadata_list})

        except Exception as e:
            # 如果发生异常，返回错误信息
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: An error occurred: {str(e)}")


    def put(self,request ):
        """
        更新文件的元数据
        """
        file_id = request.data.get('id',None)
        if not file_id:
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: id not exist")
        try:
            file_instance = KnowledgeBaseFile.objects.get(id=file_id)
        except KnowledgeBaseFile.DoesNotExist:
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: id is error")

        # 使用序列化器验证和更新文件元数据
        serializer = KnowledgeBaseFileSerializer(file_instance, data=request.data, partial=True)

        if serializer.is_valid():
            # 保存更新的文件实例
            serializer.save()
            return ResponseUtil.success(data=serializer.data)

        return ResponseUtil.error(code2=ModelCode, code3="02", message="error: An error occurred: {str(e)}")

    def delete(self,request ):
        """
        删除文件及其在 MinIO 中的存储
        """
        file_id = request.data.get('id', None)
        if not file_id:
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: id not exist")

        try:
            file_instance = KnowledgeBaseFile.objects.get(id=file_id)
        except KnowledgeBaseFile.DoesNotExist:
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: id is error")

        # 删除 MinIO 中的文件
        s3_client = boto3.client(
            's3',
            aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
            aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
            endpoint_url=settings.AWS_S3_ENDPOINT_URL
        )

        try:
            # 删除文件（假设文件的存储路径是文件名）
            s3_client.delete_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=file_instance.file.name)
        except Exception as e:
            return ResponseUtil.error(code2=ModelCode, code3="02", message="error: internal server error")

        # 删除数据库记录
        file_instance.delete()

        return ResponseUtil.success()

class KnowledgesView(APIView):

    def post(self,request):
        """
        创建新的知识库
        """
        name = request.data['name']
        version = request.data['version']

        if not name or not version :
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: Missing required fields")

        new_file = KnowledgeBase(
            name=name,
            version=version
        )
        new_file.save()
        return ResponseUtil.success(data={})


    def get(self,request):
        """
        获取知识库列表或单个知识库（根据是否提供 id）
        支持分页
        """
        file_id = request.GET.get('id', None)
        if file_id:
            try:
                knowledge_base = KnowledgeBase.objects.get(id=file_id)
                serializer = KnowledgeBaseSerializer(knowledge_base)
                knowledge_metadata_list = [serializer.data]
                return ResponseUtil.success(data={'knowledge_metadata_list': knowledge_metadata_list})
            except KnowledgeBase.DoesNotExist:
                return ResponseUtil.error(code2=ModelCode, code3="01", message="error: KnowledgeBase not found")
        else:
            knowledge_bases = KnowledgeBase.objects.all()
            # 将查询结果转换为列表
            knowledge_metadata_list = list(knowledge_bases.values(
                'id', 'name', 'version', 'created_at'
            ))

            return ResponseUtil.success(data={'knowledge_metadata_list': knowledge_metadata_list})


    def put(self,request):
        """
        更新指定 ID 的知识库
        """
        file_id = request.data['id']
        try:
            knowledge_base = KnowledgeBase.objects.get(id=file_id)
        except KnowledgeBase.DoesNotExist:
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: KnowledgeBase not found")

        name = request.data['name']
        version = request.data['version']
        data = {
            "name":name,
            "version":version
        }
        serializer = KnowledgeBaseSerializer(knowledge_base, data=data, partial=True)

        if serializer.is_valid():
            serializer.save()
            return ResponseUtil.success()

        return ResponseUtil.error(code2=ModelCode, code3="02", message="error: internal server error")


    def delete(self,request):
        """
        删除指定 ID 的知识库
        """
        file_id = request.GET.get('id', None)
        try:
            knowledge_base = KnowledgeBase.objects.get(id=file_id)
        except KnowledgeBase.DoesNotExist:
            return ResponseUtil.error(code2=ModelCode, code3="01", message="error: KnowledgeBase not found")

        knowledge_base.delete()
        return ResponseUtil.success()